{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# GRU Sentiment Classifier"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook, we use a GRU to classify IMDB movie reviews by their sentiment."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/the-deep-learners/deep-learning-illustrated/blob/master/notebooks/gru_sentiment_classifier.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load dependencies"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import keras\n",
    "from keras.datasets import imdb\n",
    "from keras.preprocessing.sequence import pad_sequences\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense, Dropout, Embedding, SpatialDropout1D\n",
    "from keras.layers import GRU # new! \n",
    "from keras.callbacks import ModelCheckpoint\n",
    "import os\n",
    "from sklearn.metrics import roc_auc_score \n",
    "import matplotlib.pyplot as plt \n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Set hyperparameters"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# output directory name:\n",
    "output_dir = 'model_output/gru'\n",
    "\n",
    "# training:\n",
    "epochs = 4\n",
    "batch_size = 128\n",
    "\n",
    "# vector-space embedding: \n",
    "n_dim = 64 \n",
    "n_unique_words = 10000 \n",
    "max_review_length = 100 # lowered due to vanishing gradient over time\n",
    "pad_type = trunc_type = 'pre'\n",
    "drop_embed = 0.2 \n",
    "\n",
    "# GRU layer architecture:\n",
    "n_gru = 256 \n",
    "drop_gru = 0.2\n",
    "\n",
    "# dense layer architecture: \n",
    "# n_dense = 256\n",
    "# dropout = 0.2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Load data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x_train, y_train), (x_valid, y_valid) = imdb.load_data(num_words=n_unique_words) # removed n_words_to_skip"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Preprocess data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "x_train = pad_sequences(x_train, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)\n",
    "x_valid = pad_sequences(x_valid, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Design neural network architecture"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Sequential()\n",
    "model.add(Embedding(n_unique_words, n_dim, input_length=max_review_length)) \n",
    "model.add(SpatialDropout1D(drop_embed))\n",
    "model.add(GRU(n_gru, dropout=drop_gru))\n",
    "# model.add(Dense(n_dense, activation='relu')) # typically don't see top dense layer in NLP like in \n",
    "# model.add(Dropout(dropout))\n",
    "model.add(Dense(1, activation='sigmoid'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "embedding_1 (Embedding)      (None, 100, 64)           640000    \n",
      "_________________________________________________________________\n",
      "spatial_dropout1d_1 (Spatial (None, 100, 64)           0         \n",
      "_________________________________________________________________\n",
      "gru_1 (GRU)                  (None, 256)               246528    \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 1)                 257       \n",
      "=================================================================\n",
      "Total params: 886,785\n",
      "Trainable params: 886,785\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Configure model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "modelcheckpoint = ModelCheckpoint(filepath=output_dir+\"/weights.{epoch:02d}.hdf5\")\n",
    "if not os.path.exists(output_dir):\n",
    "    os.makedirs(output_dir)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Train!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train on 25000 samples, validate on 25000 samples\n",
      "Epoch 1/4\n",
      "25000/25000 [==============================] - 44s 2ms/step - loss: 0.4918 - acc: 0.7478 - val_loss: 0.3749 - val_acc: 0.8353\n",
      "Epoch 2/4\n",
      "25000/25000 [==============================] - 43s 2ms/step - loss: 0.2975 - acc: 0.8767 - val_loss: 0.3419 - val_acc: 0.8490\n",
      "Epoch 3/4\n",
      "25000/25000 [==============================] - 43s 2ms/step - loss: 0.2400 - acc: 0.9061 - val_loss: 0.3557 - val_acc: 0.8436\n",
      "Epoch 4/4\n",
      "25000/25000 [==============================] - 43s 2ms/step - loss: 0.2069 - acc: 0.9210 - val_loss: 0.3747 - val_acc: 0.8409\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x7f617d898f28>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[modelcheckpoint])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "#### Evaluate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "model.load_weights(output_dir+\"/weights.02.hdf5\") "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "y_hat = model.predict_proba(x_valid)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f61769a1be0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.hist(y_hat)\n",
    "_ = plt.axvline(x=0.5, color='orange')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'93.01'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\"{:0.2f}\".format(roc_auc_score(y_valid, y_hat)*100.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
